package com.specificgroup.jira.plugin.acpro.service.impl;

import com.specificgroup.jira.plugin.acpro.mapping.*;
import com.specificgroup.jira.plugin.acpro.model.ReviewData;
import com.specificgroup.jira.plugin.acpro.model.Settings;
import com.specificgroup.jira.plugin.acpro.model.acpro.AcproItem;
import com.specificgroup.jira.plugin.acpro.model.acpro.AcproProject;
import com.specificgroup.jira.plugin.acpro.model.jira.JiraProject;
import com.specificgroup.jira.plugin.acpro.model.jira.JiraProjectComponent;
import com.specificgroup.jira.plugin.acpro.service.JiraAcproPluginJiraManager;
import com.specificgroup.jira.plugin.acpro.service.ReviewBuilder;
import com.specificgroup.jira.plugin.acpro.util.AcproUtil;
import com.specificgroup.jira.plugin.acpro.util.ObjectsBuilder;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.CategoryType;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.GetProjectResponseType;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.GetUserListResponseType;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.ItemType;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.StatusType;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.UrgencyType;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.UserType;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Ivan Holub
 */
public class ReviewBuilderImpl implements ReviewBuilder {

    private Logger log = Logger.getLogger(getClass());

    private JiraAcproPluginJiraManager jiraAcproPluginJiraManager;

    public ReviewBuilderImpl(JiraAcproPluginJiraManager jiraAcproPluginJiraManager) {
        this.jiraAcproPluginJiraManager = jiraAcproPluginJiraManager;
    }

    public ReviewData getReviewData(Settings settings) {

        ReviewData retValue = new ReviewData();

        buildReviewAcproProject(retValue, settings);

        buildReviewJiraProject(retValue, settings);

        buildReviewUserMapping(retValue, settings);

        buildReviewIssueTypeMapping(retValue, settings);

        buildReviewPriorityMapping(retValue, settings);

        buildReviewStatusMapping(retValue, settings);

        buildReviewResolutionMapping(retValue, settings);

        buildReviewProjectVersionMapping(retValue, settings);

        return retValue;
    }

    private void buildReviewAcproProject(ReviewData reviewData, Settings settings) {
        GetProjectResponseType projectResponse = settings.getAcproResponse().getProjectResponse();
        AcproProject acproProject = new AcproProject();
        acproProject.setKey(projectResponse.getProjectKey());
        acproProject.setName(projectResponse.getProjectName());

        reviewData.setAcproProject(acproProject);

        List<AcproItem> acproItems = new ArrayList<AcproItem>();
        List<ItemType> acproSelectedXmlItems = settings.getAcproResponse().getAcproSelectedXmlItems();
        for (ItemType it: acproSelectedXmlItems) {
            AcproItem item = ObjectsBuilder.buildAcproItem(it);
            acproItems.add(item);
        }

        reviewData.setAcproItems(acproItems);
    }

    private void buildReviewJiraProject(ReviewData reviewData, Settings settings) {
        JiraProject jiraProject = null;
        List<JiraProject> jiraProjects = jiraAcproPluginJiraManager.getJiraProjects();
        Long jiraProjectId = settings.getJiraProjectId();
        for (JiraProject p: jiraProjects) {
            if (jiraProjectId.equals(p.getId())) {
                jiraProject = p;
                break;
            }
        }

        reviewData.setJiraProject(jiraProject);

        List<Long> jiraProjectComponentsIds = settings.getJiraProjectComponentsIds();
        if (jiraProjectComponentsIds != null) {
            List<JiraProjectComponent> jiraProjectComponents = new ArrayList<JiraProjectComponent>();
            List<JiraProjectComponent> jiaProjectComponents = jiraAcproPluginJiraManager.getJiraProjectComponents(jiraProjectId);
            for (Long id: jiraProjectComponentsIds) {
                for (JiraProjectComponent c: jiaProjectComponents) {
                    if (id.equals(c.getId())) {
                        jiraProjectComponents.add(c);
                    }
                }
            }

            reviewData.setJiraProjectComponents(jiraProjectComponents);
        }
    }

    private void buildReviewUserMapping(ReviewData reviewData, Settings settings) {
        List<MappingEntry<AcproUser, JiraUser>> userMappingList = new ArrayList<MappingEntry<AcproUser, JiraUser>>();
        Map<String, String> userMapping = settings.getUsersMapping();
        GetUserListResponseType userListResponse = settings.getAcproResponse().getUserListResponse();
        Map<String, UserType> acproUsersMap = AcproUtil.buildUsersMap(userListResponse);
        Map<String, JiraUser> jiraUsers = jiraAcproPluginJiraManager.getJiraUsersMap();
        for (String acproUserKey: userMapping.keySet()) {
            String jiraUserName = userMapping.get(acproUserKey);
            UserType xmlUser = acproUsersMap.get(acproUserKey);
            AcproUser acproUser = ObjectsBuilder.buildAcproUser(xmlUser);
            JiraUser jiraUser = jiraUsers.get(jiraUserName);
            MappingEntry<AcproUser, JiraUser> mappingEntry = new MappingEntry<AcproUser, JiraUser>();
            mappingEntry.setAcproObj(acproUser);
            mappingEntry.setJiraObj(jiraUser);
            userMappingList.add(mappingEntry);
        }

        reviewData.setUserMapping(userMappingList);

        List<MappingEntry<NotifyCCUser, JiraUser>> notifyCCMappingList = new ArrayList<MappingEntry<NotifyCCUser, JiraUser>>();
        Map<String, String> notifyCCMapping = settings.getNotifyCCMapping();
        for (String acproEmail: notifyCCMapping.keySet()) {
            String jiraUserName = notifyCCMapping.get(acproEmail);
            NotifyCCUser notifyCCUser = new NotifyCCUser();
            notifyCCUser.setEmail(acproEmail);
            JiraUser jiraUser = jiraUsers.get(jiraUserName);
            MappingEntry<NotifyCCUser, JiraUser> mappingEntry = new MappingEntry<NotifyCCUser, JiraUser>();
            mappingEntry.setAcproObj(notifyCCUser);
            mappingEntry.setJiraObj(jiraUser);
            notifyCCMappingList.add(mappingEntry);
        }

        reviewData.setNotifyCCMapping(notifyCCMappingList);
    }

    private void buildReviewIssueTypeMapping(ReviewData reviewData, Settings settings) {
        List<MappingEntry<AcproCategory, JiraIssueType>> issueTypeMappingList = new ArrayList<MappingEntry<AcproCategory, JiraIssueType>>();
        Map<String, String> issueTypeMapping = settings.getIssueTypeMapping();
        GetProjectResponseType projectResponse = settings.getAcproResponse().getProjectResponse();
        List<CategoryType> xmlCategoties = projectResponse.getCategories().getCategory();
        Map<String, CategoryType> categoriesMap = buildAcproCategoryMap(xmlCategoties);
        Map<String, JiraIssueType> jiraIssueTypes = jiraAcproPluginJiraManager.getJiraIssueTypesMap();
        for (String acproKey: issueTypeMapping.keySet()) {
            String jiraId = issueTypeMapping.get(acproKey);
            CategoryType xmlCategory = categoriesMap.get(acproKey);
            AcproCategory acproCategory = ObjectsBuilder.buildAcproCategory(xmlCategory);
            JiraIssueType jiraIssueType = jiraIssueTypes.get(jiraId);
            MappingEntry<AcproCategory, JiraIssueType> mappingEntry = new MappingEntry<AcproCategory, JiraIssueType>();
            mappingEntry.setAcproObj(acproCategory);
            mappingEntry.setJiraObj(jiraIssueType);
            issueTypeMappingList.add(mappingEntry);
        }

        reviewData.setIssueTypeMapping(issueTypeMappingList);

        String categoryIsNotSetJiraIssueTypeIdMapping = settings.getCategoryIsNotSetJiraIssueTypeIdMapping();
        JiraIssueType categoryIsNotSetJiraIssueTypeMapping = jiraIssueTypes.get(categoryIsNotSetJiraIssueTypeIdMapping);
        reviewData.setCategoryIsNotSetJiraIssueTypeMapping(categoryIsNotSetJiraIssueTypeMapping);
    }

    private void buildReviewPriorityMapping(ReviewData reviewData, Settings settings) {
        List<MappingEntry<AcproUrgency, JiraPriority>> priorityMappingList = new ArrayList<MappingEntry<AcproUrgency, JiraPriority>>();
        Map<String, String> priorityMapping = settings.getPriorityMapping();
        GetProjectResponseType projectResponse = settings.getAcproResponse().getProjectResponse();
        List<UrgencyType> xmlPriorities = projectResponse.getUrgencies().getUrgency();
        Map<String, UrgencyType> urgenciesMap = buildAcproUrgencyMap(xmlPriorities);
        Map<String, JiraPriority> jiraPriorities = jiraAcproPluginJiraManager.getJiraPrioritiesMap();
        for (String acproKey: priorityMapping.keySet()) {
            String jiraId = priorityMapping.get(acproKey);
            UrgencyType xmlUrgency = urgenciesMap.get(acproKey);
            AcproUrgency acproUrgency = ObjectsBuilder.buildAcproUrgency(xmlUrgency);
            JiraPriority jiraPriority = jiraPriorities.get(jiraId);
            MappingEntry<AcproUrgency, JiraPriority> mappingEntry = new MappingEntry<AcproUrgency, JiraPriority>();
            mappingEntry.setAcproObj(acproUrgency);
            mappingEntry.setJiraObj(jiraPriority);
            priorityMappingList.add(mappingEntry);
        }

        reviewData.setPriorityMapping(priorityMappingList);
    }

    private void buildReviewStatusMapping(ReviewData reviewData, Settings settings) {
        List<MappingEntry<AcproStatus, JiraStatus>> statusMappingList = new ArrayList<MappingEntry<AcproStatus, JiraStatus>>();
        Map<String, String> statusMapping = settings.getStatusMapping();
        GetProjectResponseType projectResponse = settings.getAcproResponse().getProjectResponse();
        List<StatusType> xmlStatuses = projectResponse.getStatuses().getStatus();
        Map<String, StatusType> urgenciesMap = buildAcproStatusMap(xmlStatuses);
        Map<String, JiraStatus> jiraStatuses = jiraAcproPluginJiraManager.getJiraStatusesMap();
        for (String acproKey: statusMapping.keySet()) {
            String jiraId = statusMapping.get(acproKey);
            StatusType xmlStatus = urgenciesMap.get(acproKey);
            AcproStatus acproStatus = ObjectsBuilder.buildAcproStatus(xmlStatus);
            JiraStatus jiraStatus = jiraStatuses.get(jiraId);
            MappingEntry<AcproStatus, JiraStatus> mappingEntry = new MappingEntry<AcproStatus, JiraStatus>();
            mappingEntry.setAcproObj(acproStatus);
            mappingEntry.setJiraObj(jiraStatus);
            statusMappingList.add(mappingEntry);
        }

        reviewData.setStatusMapping(statusMappingList);
    }

    private void buildReviewResolutionMapping(ReviewData reviewData, Settings settings) {
        List<MappingEntry<AcproStatus, JiraResolution>> resolutionMappingList = new ArrayList<MappingEntry<AcproStatus, JiraResolution>>();
        Map<String, String> statusMapping = settings.getResolutionMapping();
        GetProjectResponseType projectResponse = settings.getAcproResponse().getProjectResponse();
        List<StatusType> xmlStatuses = projectResponse.getStatuses().getStatus();
        Map<String, StatusType> urgenciesMap = buildAcproStatusMap(xmlStatuses);
        Map<String, JiraResolution> jiraStatuses = jiraAcproPluginJiraManager.getJiraResolutionMap();
        for (String acproKey: statusMapping.keySet()) {
            String jiraId = statusMapping.get(acproKey);
            if (jiraId != null) {
                StatusType xmlStatus = urgenciesMap.get(acproKey);
                AcproStatus acproStatus = ObjectsBuilder.buildAcproStatus(xmlStatus);
                JiraResolution jiraStatus = jiraStatuses.get(jiraId);
                MappingEntry<AcproStatus, JiraResolution> mappingEntry = new MappingEntry<AcproStatus, JiraResolution>();
                mappingEntry.setAcproObj(acproStatus);
                mappingEntry.setJiraObj(jiraStatus);
                resolutionMappingList.add(mappingEntry);
            }
        }

        reviewData.setResolutionMapping(resolutionMappingList);
    }

    private void buildReviewProjectVersionMapping(ReviewData reviewData, Settings settings) {
        Long jiraProjectId = settings.getJiraProjectId();
        List<MappingEntry<AcproProductVersion, JiraProjectVersion>> projectVersionMappingList = new ArrayList<MappingEntry<AcproProductVersion, JiraProjectVersion>>();
        Map<String, Long> mapping = settings.getProjectVersionMapping();
        Map<Long, JiraProjectVersion> map = jiraAcproPluginJiraManager.getJiraProjectVersionsMap(jiraProjectId);
        for (String name: mapping.keySet()) {
            Long jiraId = mapping.get(name);
            AcproProductVersion acproObj = new AcproProductVersion();
            acproObj.setName(name);
            JiraProjectVersion jiraObj = map.get(jiraId);
            MappingEntry<AcproProductVersion, JiraProjectVersion> mappingEntry = new MappingEntry<AcproProductVersion, JiraProjectVersion>();
            mappingEntry.setAcproObj(acproObj);
            mappingEntry.setJiraObj(jiraObj);
            projectVersionMappingList.add(mappingEntry);
        }

        reviewData.setProjectVersionMapping(projectVersionMappingList);
    }

    private Map<String, CategoryType> buildAcproCategoryMap(List<CategoryType> categoties) {
        Map<String, CategoryType> retValue = new HashMap<String, CategoryType>();
        for (CategoryType item: categoties) {
            retValue.put(item.getKey(), item);
        }
        return retValue;
    }

    private Map<String, UrgencyType> buildAcproUrgencyMap(List<UrgencyType> urgencies) {
        Map<String, UrgencyType> retValue = new HashMap<String, UrgencyType>();
        for (UrgencyType item: urgencies) {
            retValue.put(item.getKey(), item);
        }
        return retValue;
    }

    private Map<String, StatusType> buildAcproStatusMap(List<StatusType> statuses) {
        Map<String, StatusType> retValue = new HashMap<String, StatusType>();
        for (StatusType item: statuses) {
            retValue.put(item.getKey(), item);
        }
        return retValue;
    }
    
}
